-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: macOS feasibility incorporation #71
base: main
Are you sure you want to change the base?
Conversation
probe_src/libprobe/src/prov_buffer.c
Outdated
@@ -37,35 +42,37 @@ int copy(const struct Path* path) { | |||
* We promise not to read those fields in this function. | |||
*/ | |||
static void prov_log_try(struct Op op) { | |||
#ifdef CLONE_VFORK |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we not need this ifdef
since x & CLONE_VFORK
will always be 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
incorporated ( removed CLONE_VFORK
definition from prov_buffer.c
)
* Generate a macOS interpose struct | ||
* Types from: http://opensource.apple.com/source/dyld/dyld-210.2.3/include/mach-o/dyld-interposing.h | ||
*/ | ||
#define OSX_INTERPOSE_STRUCT(NEW, OLD) \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally, pre-processor macros would be the right way to eliminate duplicated code.
In this particular case, the C code is generated from Python in generator/gen_libc_hooks.py
, and there isn't a good way to emit code that calls the C preprocessor macros. It would be better to implement the logic directly in Python.
Therefore, for the above file, can you write out what it should be after expanding the pre-processor macros?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My concern is that in Linux, the shared library needs to define a function with the name we want to interpose (e.g., open
), and load the real/underlying function with a new name (e.g., unwrapped_open
) using dlsym
.
In Mac, it seems that we define a function with the new name (e.g., my_open
), and call the real/underlying function with the original name (open
)
__attribute__ ((section ("__DATA,__interpose"))) = {
(const void*)(unsigned long)&my_open,
(const void*)(unsigned long)&open
};
The meaning of the name open
is reversed: in Linux its the wrapper; in Mac it's the underlying function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is of course salvageable. We should always call unwrapped_open
and wrapped_open
to eliminate confusion, but alias one of them to the "original name" based on platform.
#ifdef linux
#define wrapped_open open
#else if apple
#define unwrapped_open open
#endif
We hardly ever call the wrapped versions, always the unwrapped, which are already called as unwrapped_
in our code.
But I wanted to confirm that this is the only way to interpose functions in Mac before doing that. So please let me know.
Co-authored-by: Jenna Fligor <[email protected]>
Co-authored-by: Jenna Fligor <[email protected]>
Co-authored-by: Jenna Fligor <[email protected]>
if (!__process_inited) { | ||
__process_inited = true; | ||
|
||
DEBUG("Initializing process"); | ||
init_function_pointers(); | ||
check_function_pointers(); | ||
init_process_global_state(); | ||
|
||
pthread_key_create(&tld_key, free); | ||
|
||
__process_inited_done = true; | ||
} | ||
while (!__process_inited_done) { | ||
sched_yield(); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there may be a race if multiple threads try to init at the same. I think I specified the algorihtm incorrectly (slightly the first time). Here's what it should be:
if (is process inited) {
if (test_and_set(is first thread)) {
... do your process initialization you have here
is process initted = true;
} else {
// process is not initted, but someone else is already handling it.
while (!process is inited) { sched_yield(); }
}
}
// process is inited here. Yay!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test_and_set
should be replaced __sync_bool_compare_and_swap
Description:
Making
PROBE
feasible for macOS systems.Changes:
Worked out how to interpose in macOS, added a test program (
test_program.c
), which interposes thefopen
call and calls the underlying call. The mentioned changes are in filesinterpose.h
,interpose.c
,test_program.c
. Steps to runtest_program.c
with interposition:clang -dynamiclib -o libinterpose.dylib interpose.c
clang -o test_program test_program.c
export DYLD_INSERT_LIBRARIES=$(pwd)/libinterpose.dylib
./test_program
Added macOS architecture in
flake.nix
Edited
Makefile
to be adjustable for both linux and macOS.The rest of the changes have been made either to add replacement libraries for macOS, added
ifndef
with code blocks which are linux or macOS specific. Added dummy definitions liketypedef thrd_t int
for macros which are not available on macOS. Guarded dummy definitions withifndef
Questions and next steps: